﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using OOO.Scene;

namespace TestMain
{
	public class MyTimer
	{
 		[DllImport("kernel32.dll")]
		private static extern long GetTickCount();

		private long _startTick = 0;

		public MyTimer()
		{
			Reset();
		}

		public void Reset()
		{
			_startTick = GetTickCount();
		}

		public long GetTicks()
		{
			return GetTickCount() - _startTick;
		}
	}

	public class MainForm : Form
	{
		private bool _alive = true;

		private const int WM_KEYDOWN = 0x0100;
		private const int WM_KEYUP = 0x0101;
		private const int VK_DOWN = 0x28;
		private const int VK_RIGHT = 0x27;
		private const int VK_UP = 0x26;
		private const int VK_LEFT = 0x25;
		private const int VK_SPACE = 0x20;
		private const int VK_ENTER = 0x0D;

		private TimeSpan _stepSize = TimeSpan.FromMilliseconds(10); //10ms

		private StartState _startState;
		private MainState _mainState;

		private IGameState _currentState;

		public MainForm()
		{
			this.ClientSize = new Size(800, 430);

			RenderManager.Initailize(this.CreateGraphics(), 800, 430);

			_startState = new StartState();

			_startState.StartGameEvent += () => 
			{
				_mainState = new MainState();
				_mainState.GameOverEvent += () =>
				{
					_currentState = _startState;
				};
				_currentState = _mainState;
			};

			_startState.ExitGameEvent += () =>
			{
				this.Close();
			};

			_currentState = _startState;

			MouseDown += (s, e) => {
				if (_currentState is StartState)
				{
					(_currentState as StartState).MouseDown(e.X, e.Y);
				}
			};

			MouseUp += (s, e) =>
			{
				if (_currentState is StartState)
				{
					(_currentState as StartState).MouseUp(e.X, e.Y);
				}
			};
		}

		public void MainLoop()
		{
			DateTime lastExecutionTime = DateTime.Now;

			DateTime last = DateTime.Now;

			while (_alive)
			{
				DateTime now = DateTime.Now;

				while (lastExecutionTime + _stepSize < now)
				{
					Application.DoEvents();//alive update here

					Update((int)_stepSize.TotalMilliseconds);

					lastExecutionTime += _stepSize;
				}

				if (_alive)
				{
					Render();
				}
			}
		}

		protected override void OnClosed(EventArgs e)
		{
			_alive = false;

			base.OnClosed(e);
		}

		private void Update(int elapsedMS)
		{
			_currentState.Update(elapsedMS);
		}

		private void Render()
		{
			_currentState.Render();
		}

		protected override void WndProc(ref Message m)
		{
			if (m.Msg == WM_KEYDOWN)
			{
				int repeatCount = (int)m.LParam & 0xFFFF;
				KeyboardEvent keyEvent = null;
				DateTime now = DateTime.Now;
				
				switch ((int)m.WParam)
				{
					case VK_RIGHT:
						keyEvent = new KeyboardEvent(KEY.KEY_RIGHT, KEY_TYPE.KEY_DOWN, repeatCount, now);
						break;
					case VK_LEFT:
						keyEvent = new KeyboardEvent(KEY.KEY_LEFT, KEY_TYPE.KEY_DOWN, repeatCount, now);
						break;
					case VK_DOWN:
						keyEvent = new KeyboardEvent(KEY.KEY_DOWN, KEY_TYPE.KEY_DOWN, repeatCount, now);
						break;
					case VK_UP:
						keyEvent = new KeyboardEvent(KEY.KEY_UP, KEY_TYPE.KEY_DOWN, repeatCount, now);
						break;
					case VK_SPACE:
						keyEvent = new KeyboardEvent(KEY.KEY_SPACE, KEY_TYPE.KEY_DOWN, repeatCount, now);
						break;
					case VK_ENTER:
						keyEvent = new KeyboardEvent(KEY.KEY_ENTER, KEY_TYPE.KEY_DOWN, repeatCount, now);
						break;
					case 'a':
					case 'A':
						keyEvent = new KeyboardEvent(KEY.KEY_A, KEY_TYPE.KEY_DOWN, repeatCount, now);
						break;
				}

				if (keyEvent != null)
					KeyboardManager.Instance.ChangeKeyState(keyEvent);
			}
			else if (m.Msg == WM_KEYUP)
			{
				int repeatCount = (int)m.LParam & 0xFFFF;
				KeyboardEvent keyEvent = null;
				DateTime now = DateTime.Now;

				switch ((int)m.WParam)
				{
					case VK_RIGHT:
						keyEvent = new KeyboardEvent(KEY.KEY_RIGHT, KEY_TYPE.KEY_UP, repeatCount, now);
						break;
					case VK_LEFT:
						keyEvent = new KeyboardEvent(KEY.KEY_LEFT, KEY_TYPE.KEY_UP, repeatCount, now);
						break;
					case VK_DOWN:
						keyEvent = new KeyboardEvent(KEY.KEY_DOWN, KEY_TYPE.KEY_UP, repeatCount, now);
						break;
					case VK_UP:
						keyEvent = new KeyboardEvent(KEY.KEY_UP, KEY_TYPE.KEY_UP, repeatCount, now);
						break;
					case VK_SPACE:
						keyEvent = new KeyboardEvent(KEY.KEY_SPACE, KEY_TYPE.KEY_UP, repeatCount, now);
						break;
					case VK_ENTER:
						keyEvent = new KeyboardEvent(KEY.KEY_ENTER, KEY_TYPE.KEY_UP, repeatCount, now);
						KeyboardManager.Instance.SwitchEnter();
						break;
					case 'a':
					case 'A':
						keyEvent = new KeyboardEvent(KEY.KEY_A, KEY_TYPE.KEY_UP, repeatCount, now);
						KeyboardManager.Instance.AddAlphabet((int)m.WParam);
						break;
					default:
						int val = (int)m.WParam;
						if ((val >= (int)'a' && val <= (int)'z') ||
							(val >= (int)'A' && val <= (int)'Z') ||
							(val >= (int)'0' && val <= (int)'9') ||
							(val == (int)'!') || (val == (int)'?'))
						{
							KeyboardManager.Instance.AddAlphabet(val);
						}
						break;
				}

				if (keyEvent != null)
					KeyboardManager.Instance.ChangeKeyState(keyEvent);
			}

			base.WndProc(ref m);
		}
	}
}
